#include "Memory.h"
#include <algorithm>
#include <random>       
#include <chrono>
#include <iostream>
#include <conio.h>
#include "Console.h"

using namespace std;
using namespace Course;

namespace MemorySpace
{
	Memory::Memory()
	{
		turn = 0;
		p = 0;
		r = 0;
		c = 0;
		cvv = nullptr;
		pv = nullptr;
	}

	Memory::~Memory()
	{
		delete cvv;
		delete pv;
	}

	void Memory::createBoard()
	{
		if (cvv != nullptr)
		{
			cvv->clear();
		}
		//Create the matrix for the board
		cvv = new vector<vector<Card>>(r);
		for (int i = 0; i < r; i++){
			(*cvv)[i] = vector<Card>(c);
		}

		//Create a vector containing all the "faces" that will be used
		vector<char> facev;
		char face = 'a';
		for (int i = 0; i < (r*c); i++){
			facev.push_back(face);
			//every other card get a new face, makes sure there's two of ever card
			if (i % 2 == 1){
				face++;
			}
		}
		
		//Randomly shuffle the card faces
		unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
		shuffle(facev.begin(), facev.end(), std::default_random_engine(seed));

		//Generate cards for all the vectors, filling the board
		int k = 0;
		for (int i = 0; i < r; i++){
			for (int j = 0; j < c; j++){
				(*cvv)[i][j] = Card(facev[k++]);
			}
		}
	}

	void Memory::createPlayers()
	{
		pv = new vector<Player>;
		for (int i = 0; i < p; i++){
			string name;
			cout << "Player " << i + 1 <<" name: ";
			cin >> name;
			(*pv).push_back(Player(name));
		}
	}

	void Memory::drawBoard()
	{
		Console::clrscr();
		//Draw all the cards
		for (int i = 0; i < r; i++){
			for (int j = 0; j < c; j++){
				if ((*cvv)[i][j].facingUp()){
					cout << (*cvv)[i][j].getFace() << ' ';
				}
				else
				{
					cout << "M ";
				}
			}
			cout << endl << endl;
		}
		//Print out who's turn it is
		cout << endl << (*pv)[turn].getName() << "'s turn" << endl << endl;
		//Print out the current scores
		cout << "Scores:" << endl;
		for (int i = 0; i < p; i++)
		{
			cout << (*pv)[i].getName() << ": " << (*pv)[i].getScore() << endl;
		}
	}

	void Memory::playerTurn()
	{
		//Let the player turn two cards 
		drawBoard();
		int x = 0, y = 0;
		inputHandler(x, y);
		(*cvv)[y][x].setFacingUp(true);
		int c1x = x, c1y = y;
		drawBoard();
		inputHandler(x, y);
		(*cvv)[y][x].setFacingUp(true);
		int c2x = x, c2y = y;
		drawBoard();

		//Check if the cards have the same face
		if ((*cvv)[c1y][c1x].getFace() == (*cvv)[c2y][c2x].getFace()){
			(*cvv)[c1y][c1x].removeFromBoard();
			(*cvv)[c2y][c2x].removeFromBoard();
			(*pv)[turn].setScore((*pv)[turn].getScore() + 10);
		}
		else{
			(*cvv)[c1y][c1x].setFacingUp(false);
			(*cvv)[c2y][c2x].setFacingUp(false);
			turn = (++turn) % p;
		}
		Sleep(1000);
	}

	void Memory::inputHandler(int &x, int&y)
	{
		int xpos = x, ypos = y;
		while (true){
			Console::gotoxy(xpos * 2, ypos * 2);
			char input = _getch();
			//Move left
			if (input == 75){
				if (xpos > 0){
					xpos--;
				}
				else{
					xpos = c - 1;
				}
			}
			//Move up
			else if (input == 72){
				if (ypos > 0){
					ypos--;
				}
				else{
					ypos = r - 1;
				}
			}
			//Move right
			else if (input == 77){
				if (xpos < (c - 1)){
					xpos++;
				}
				else{
					xpos = 0;
				}
			}
			//Move down
			else if (input == 80){
				if (ypos < (r - 1)){
					ypos++;
				}
				else{
					ypos = 0;
				}
			}
			//If the card is not facing up, set values and exit loop
			else if (input == 13){
				if (!(*cvv)[ypos][xpos].facingUp()){
					x = xpos;
					y = ypos;
					break;
				}
			}
		}
	}

	bool Memory::movesLeft()
	{
		for (int i = 0; i < r; i++){
			for (int j = 0; j < c; j++){
				if (!(*cvv)[i][j].facingUp()){
					return true;
				}
			}
		}
		return false;
	}
	
	void Memory::printEndScreen()
	{
		Console::clrscr();
		sortPlayers();
		cout << (*pv)[0].getName() << " won with a score of " << (*pv)[0].getScore() << endl << "----------------" << endl;
		for (int i = 1; i < p; i++)
		{
			cout << (*pv)[i].getName() << ": " << (*pv)[i].getScore() << endl;
		}
	}

	void Memory::sortPlayers()
	{
		sort((*pv).begin(), (*pv).end());
	}

	void Memory::runGame()
	{
		cout << "Number of players: ";
		cin >> p;
		cout << "Number of rows on the board: ";
		cin >> r;
		cout << "Number of columns on the board: ";
		cin >> c;
		//Make sure there's an even number of cards
		if ((r*c) % 2 != 0){
			r--;
		}
		createBoard();
		createPlayers();

		while (movesLeft()){
			playerTurn();
		}
		printEndScreen();
	}
}